///////////////////////////////////////////////////////////////////////////
//
// Spring Engine Source File.
// Copyright (C), Dengtao 2011-2021
// ----------------------------------------------------------------------
// File name:   SfSmartPtr.h
// Version:     v1.0.0
// Created:     2013/06/15 21:54 by dengtao
// Compilers:   Visual Studio 2008
// Description: 
// ----------------------------------------------------------------------
// History:
//
///////////////////////////////////////////////////////////////////////////

#ifndef _SfSmartPtr_H_
#define _SfSmartPtr_H_

#include "SfRefObject.h"

namespace Sunflower
{
	//////////////////////////////////////////////////////////////////////////
	//Summary:
	//	smart pointer.
	//////////////////////////////////////////////////////////////////////////
	template <class T>
	class SmartPtr
	{
	public:
		//
		//Summary:
		//	constructors.
		SmartPtr() 
			: m_RawPtr(SfNull) 
		{
		}

		SmartPtr(T* rawPtr) 
			: m_RawPtr(rawPtr) 
		{
			if (SfIsValidPtr(m_RawPtr))
			{
				m_RawPtr->IncRefCount();
			}
		}

		SmartPtr(const SmartPtr& other) 
			: m_RawPtr(other.m_RawPtr)
		{
			if (SfIsValidPtr(m_RawPtr))
			{
				m_RawPtr->IncRefCount();
			}
		}

		//
		//Summary:
		//	destructor.
		~SmartPtr()
		{
			if (SfIsValidPtr(m_RawPtr))
			{
				m_RawPtr->Release();
			}
		}

		//
		//Summary:
		//	override operator =
		SmartPtr& operator =(const SmartPtr& other)
		{
			if (SfIsValidPtr(other.m_RawPtr))
			{
				other.m_RawPtr->IncRefCount();
			}

			if (SfIsValidPtr(m_RawPtr))
			{
				m_RawPtr->Release();
			}

			m_RawPtr = other.m_RawPtr;

			return *this;
		}

		SmartPtr& operator =(T* rawPtr)
		{
			if (SfIsValidPtr(rawPtr))
			{
				rawPtr->IncRefCount();
			}

			if (SfIsValidPtr(m_RawPtr))
			{
				m_RawPtr->Release();
			}

			m_RawPtr = rawPtr;

			return *this;
		}

		//
		//Summary:
		//	override operator *,->
		//	returns raw pointer.
		T& operator *() const
		{
			SfAssertValidPtr(m_RawPtr);
			return *m_RawPtr;
		}

		//
		//Summary:
		//	type cast to raw pointer class type.
		operator T*() const
		{
			return m_RawPtr;
		}

		T* operator ->() const
		{
			return m_RawPtr;
		}

		//
		//Summary:
		//	return raw pointer explicitly.
		const T* GetRawPtr() const
		{
			return m_RawPtr;
		}

		T* GetRawPtr()
		{
			return m_RawPtr;
		}

		//
		//Summary:
		//	override operator == !=
		bool operator ==(T* rawPtr) const
		{
			return m_RawPtr == rawPtr;
		}

		bool operator !=(T* rawPtr) const
		{
			return m_RawPtr != rawPtr;
		}

		bool operator ==(const SmartPtr& other) const
		{
			return m_RawPtr == other.m_RawPtr;
		}

		bool operator !=(const SmartPtr& other) const
		{
			return m_RawPtr != other.m_RawPtr;
		}

	private:
		T* m_RawPtr;
	};

} // 

#define SfDeclareSmartPtr(T) typedef SmartPtr<T> T##Ptr;

#endif